<?php
/**
 * File Management
 *
 * @author      Hyper <hyper@flashbay.com>
 * @copyright   Copyright (c) 2011 (http://www.saleshero.com)
 */
class SalesHero_File
{
    /**
     * Configs
     *
     * @var array
     */
    protected $_config = array(
        'maxSize'  => 0, //KB
        'savePath' => './uploads',
    );

    /**
     * Upload result
     *
     * @var array
     */
    protected $_result = array();

    /**
     * Constructor
     *
     * @param array $config
     */
    public function __construct($config = array())
    {
        if (!empty($config)) {
            $this->setConfig($config);
        }
    }

    /**
     * Set configs
     *
     * @param  array  $config
     * @return SalesHero_File
     */
    public function setConfig(array $config)
    {
        foreach ($config as $key => $value) {
            $method = 'set' . ucfirst($key);
            if (!method_exists($this, $method)) {
                throw new Exception("Config '$key' does not exist");
            }
            $this->$method($value);
        }
        return $this;
    }

    /**
     * Set max allowed file size (0：no limit, unit：kb)
     *
     * @param  integer  $size
     * @return SalesHero_File
     */
    public function setMaxSize($size)
    {
        if ($size < 0) {
            throw new Exception('The value of max size should not be less than 0');
        }

        $this->_config['maxSize'] = (integer) $size;
        return $this;
    }

    /**
     * Set file saved path
     *
     * @param  string  $path
     * @return SalesHero_File
     */
    public function setSavePath($path)
    {
        $mkpath = $this->mkdir($path);
        $this->_config['savePath'] = rtrim($mkpath, '\\/');
        return $this;
    }

    /**
     * Create directory
     *
     * @param  string  $dir
     * @return string
     */
    public static function mkdir($dir)
    {
        if (!is_dir($dir)) {
            $mk = @mkdir($dir, 0777, true);
            if ($mk === false) {
                throw new Exception("Failed to create directory '$dir'");
            }
        }
        return $dir;
    }

    /**
     * Get file extension
     *
     * @param  string  $filename
     * @return string
     */
    public function getExtension($filename)
    {
        return strtolower(substr(strrchr($filename, '.'), 1));
    }

    /**
     * Is the file size out of limit?
     *
     * @param  integer  $size
     * @return boolean
     */
    public function isAllowSize($size)
    {
        return $this->_config['maxSize'] == 0 || ($this->_config['maxSize'] * 1024) < $size;
    }

    /**
     * Save upload file
     *
     * @param  array   $data      For example: $_FILES['fieldname']
     * @param  string  $saveName
     * @param  string  $savePath
     * @return array
     */
    public function save(array $data, $saveName = null, $savePath = null)
    {
        if (!$this->isAllowSize($data['size'])) {
            throw new Exception("The file size is out of limit ({$this->_config['maxSize']} Kb)");
        }

        empty($savePath) && $savePath = $this->_config['savePath'];
        $this->mkdir($savePath);

        $extension = $this->getExtension($data['name']);
        if (empty($saveName)) {
            $saveName = str_replace('.', '', microtime(true)) . ".$extension";
        } else {
            $saveName = strtolower($saveName);
        }

        $path = "$savePath/$saveName";
        if (!@move_uploaded_file($data['tmp_name'], $path)) {
            throw new Exception('Failed to move upload file');
        }

        return $this->_result = array(
            'filename'      => $data['name'],
            'filesize'      => $data['size'],
            'filetype'      => $data['type'],
            'extension'     => $extension,
            'path'          => $path,
        );
    }

    /**
     * Get result
     *
     * @return array
     */
    public function getResult()
    {
        return $this->_result;
    }
}